Checking the Operating Environment
CallingExitToShell
is the preferred way to terminate your application if for some reason you don't want to return to your main event loop. You might also want to callDoBadError
to terminate your application before you even get to the main event loop. This might happen if your application requires system software routines that aren't available in all operating environments. In general, if your application uses any system software routines that aren't available in all operating environments, you need to make sure that they are available in the current environment. Otherwise, your application will crash.For example, the Venn Diagrammer application uses the
FindFolder
function to find the Preferences folder containing the application's preferences file (see Listing 3-3 on page 62). BecauseFindFolder
was introduced in system software version 7.0, Venn Diagrammer will crash if it callsFindFolder
when running in an earlier system software version.To avoid crashing in environments that don't support the
FindFolder
function, the Venn Diagrammer application makes sure that the function is available before calling it. It calls theGestalt
function to see ifFindFolder
is present, as shown in Listing 9-6.Listing 9-6 Checking that
FindFolder
is present
FUNCTION IsFindFolder: Boolean; VAR myResult: OSErr; myFeature: LongInt; BEGIN IsFindFolder := FALSE; {assume it's not available} myResult := Gestalt(gestaltFindFolderAttr, myFeature); IF myResult = noErr THEN IsFindFolder := BTST(myFeature, gestaltFindFolderPresent); END;TheGestalt
function is part of the Gestalt Manager, which you can use to determine what software and hardware features are available in the current operating environment. When passed thegestaltFindFolderAttr
selector code, theGestalt
function fills in the long integer passed in its second parameter (myFeature
) with a bit field that encodes information about the features of theFindFolder
function. Currently only one bit is defined, specified using the constantgestaltFindFolderPresent
. If that bit is set, thenFindFolder
is present in the operating environment. The Venn Diagrammer application callsIsFindFolder
as follows (see Listing 3-3 on page 62):
IF IsFindFolder THEN myResult := FindFolder(kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder, myVRefNum, myDirID);If
- Note
- For complete details about using the
Gestalt
function to determine the features of the current operating environment, see the chapter "Gestalt Manager" in Inside Macintosh: Operating System Utilities.![]()
FindFolder
function isn't available, Venn Diagrammer looks in the default directory instead of in the Preferences folder for the user's preferences file. This isn't the best strategy possible, but it's good enough for a simple application like Venn Diagrammer. More generally, however, you need to decide what the base system software requirements of your application are and how you want to react if necessary services aren't available. In some cases, working around a problem isn't so easy. In those cases, informing the user that your software won't run in the current system configuration and then exiting is probably the right thing to do.A second way to determine the availability of a particular system software routine is to test directly for the existence of the routine by inspecting its trap number (a number that identifies each system software routine), using the technique illustrated in Listing 9-7. You should use this method to test for the existence of routines not included in managers about which
Gestalt
can report.Listing 9-7 Determining whether a trap is available
FUNCTION NumToolboxTraps: Integer; BEGIN IF NGetTrapAddress(_InitGraf, ToolTrap) = NGetTrapAddress($AA6E, ToolTrap) THEN NumToolboxTraps := $200 ELSE NumToolboxTraps := $400; END; FUNCTION GetTrapType (theTrap: Integer): TrapType; CONST TrapMask = $0800; BEGIN IF BAND(theTrap, TrapMask) > 0 THEN GetTrapType := ToolTrap ELSE GetTrapType := OSTrap; END; FUNCTION TrapAvailable (theTrap: Integer): Boolean; VAR tType: TrapType; BEGIN tType := GetTrapType(theTrap); IF tType = ToolTrap THEN BEGIN theTrap := BAND(theTrap, $07FF); IF theTrap >= NumToolboxTraps THEN theTrap := _Unimplemented; END; TrapAvailable := NGetTrapAddress(theTrap, tType) <> NGetTrapAddress(_Unimplemented, ToolTrap); END;Listing 9-8 shows how to use theTrapAvailable
function defined in Listing 9-7 to determine whether theWaitNextEvent
function is available.Listing 9-8 Checking for the availability of the
WaitNextEvent
function
FUNCTION WNEAvailable: Boolean; CONST _WaitNextEvent = $A860; {trap number of WaitNextEvent} BEGIN WNEAvailable := TrapAvailable(_WaitNextEvent); END;TheNumToolboxTraps
function relies on the fact that theInitGraf
trap (trap number $A86E) is always implemented. If the trap dispatch table is large enough (that is, has more than $200 entries), then $AA6E always points to either_Unimplemented
or something else, but never toInitGraf
. As a result, you can check the size of the trap dispatch table by checking to see if the address of trap $A86E is the same as $AA6E.After receiving the information about the size of the dispatch table, the
TrapAvailable
function first checks to see if the trap to be tested has a trap number greater than the total number of traps available on the machine. If so, it sets thetheTrap
variable to_Unimplemented
before testing it against the_Unimplemented
trap. See the discussion of the trap dispatch table utilities in Inside Macintosh: Operating System Utilities for complete details on trap numbers and the trap dispatch table.
- IMPORTANT
- There's one final twist in this story. Your software development system might provide glue routines that mimic the operation of some system software routines, thereby allowing you to call them in earlier system software versions. (For instance, MPW versions 3.2 and later provide glue that allows you to call
FindFolder
in system software versions prior to 7.0.) However, you cannot in general useGestalt
or the technique shown in Listing 9-7 to test for the availability of routines provided as glue. Instead, you'll need to consult the documentation for your development system to find out what glue routines it provides.![]()